require 'digest/sha1'

# password and password_confirmation are not stored in the database
# Instead a hashed_password is stored and variables are made to store the 
# raw text.

# Any fields that are not to be updated by a web form should be protected!

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups
  has_many :forums
  has_many :posts
  has_one :profile
  
  # validations (subject to change when specs change)
  validates_length_of :login, :within => 3..20
  validates_length_of :password, :within => 5..20
  validates_presence_of :login, :email, :password, :password_confirmation, :salt
  validates_uniqueness_of :login, :email
  validates_confirmation_of :password
  validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, 
            :message => "Invalid email"
  
  # by protecting id and salt we prevent users from setting them by issuing a 
  # post request.
  attr_protected :id, :salt
  attr_accessor :password, :password_confirmation
    
  # pretty sure this works, not tested..
  def in_groups?(grps)
    my_groups = self.groups.map{|g| g.name}
    grps.each do |g|
      if my_groups.include?(g)
        return true
      end
    end
    return false
  end
  
  
  def self.authenticate(login, pass)
    u=find(:first, :conditions=>["login = ?", login])
    return nil if u.nil?
    return u if User.encrypt(pass, u.salt)==u.hashed_password
    nil
  end 
  
  def password=(pass)
    @password=pass
    self.salt = User.random_string(10) if !self.salt?
    self.hashed_password = User.encrypt(@password, self.salt)
  end

  def send_new_password
    new_pass = User.random_string(10)
    self.password = self.password_confirmation = new_pass
    self.save
    Notifications.deliver_forgot_password(self.email, self.login, new_pass)
  end

  protected

  def self.encrypt(pass, salt)
    Digest::SHA1.hexdigest(pass+salt)
  end

  def self.random_string(len)
    #generat a random password consisting of strings and digits
    chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
    newpass = ""
    1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
    return newpass
  end

end